/**
 * @file ring_buffer.h
 * @author Dustin Balise
 * @date 8/25/11
 * 
 * @brief The public interface for the ring buffer API.
 *
 * @section License
 *
 * Copyright © 2011 Dustin R. Balise
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 
 * permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the 
 * Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef RING_H
#define RING_H

#include <stdlib.h>
#include <stdbool.h>


/*
 *  Constants
 */
// Intentionally left blank.


/*
 *  Types and structures.
 */

/**
 * A ring buffer instance.
 *
 * @see ring_buffer_init
 */
typedef struct {
    /** The pointer to the ring buffer. */
    void * p_buffer;
    
    /** The pointer to the current starting location within the ring buffer. */
    void * p_start;
    
    /** The size of the ring buffer in bytes. */
    size_t size;
    
    /** The size of a single element in bytes. */
    size_t element_size;
    
    /** A counter for write operations to the ring buffer. */
    long long int c_writes;
    
    /** A counter for read operations from the ring buffer. */
    long long int c_reads;
    
    /**
     * A pointer to a function that fills the ring buffer with data.
     * @see ring_buffer_init
     */
    bool (*append)(void * p_destination, size_t max_to_append, size_t * p_appended);
    
    /** A pointer to a function that resets the data source. */
    void (*reset_data_source)(void);
    
    /** 
     * A pointer to a function that allows the ring buffer routines to be interrupt or thread safe as desired by
     * entering a critical state.
     */
    void (*enter_critical)(void);
    
    /**
     * A pointer to a function that allows the ring buffer routines to exit the interrupt and/or thread safe 
     * critical state.
     */
    void (*exit_critical)(void);
} ring_buffer_t;

/**
 * The ring buffer initialization settings.
 */
typedef struct {
    void * p_buffer;
    size_t buffer_size;
    size_t element_size;
    bool (*append)(void * p_destination, size_t max_to_append, size_t * p_appended);
    void (*reset_data_source)(void);
    void (*enter_critical)(void);
    void (*exit_critical)(void);
} ring_buffer_init_t;


/*
 *  Public functions.
 */
void ring_buffer_defaults(ring_buffer_init_t * p_init);

void ring_buffer_init(ring_buffer_t * p_circ, 
                      void * p_buffer, 
                      size_t buffer_size,
                      bool (*append)(void * p_destination, size_t max_to_append, size_t * p_appended),
                      void (*reset_data_source)(void),
                      void (*enter_critical)(void),
                      void (*exit_critical)(void));

bool ring_buffer_append(ring_buffer_t * p_circ, size_t * p_appended);

bool ring_buffer_remove(ring_buffer_t * p_circ, 
                        void * p_destination, 
                        size_t size, 
                        size_t * p_size_removed);

bool ring_buffer_peek(const ring_buffer_t * p_circ, 
                      size_t offset, 
                      void * p_destination, 
                      size_t size,
                      size_t * p_size_peeked);

void ring_buffer_reset(ring_buffer_t * p_circ);


#endif // RING_BUFFER_H
